package cn.blnp.net.flowable.boot.localize.dynamic.sign;

import cn.blnp.net.flowable.boot.service.TaskRecallService;
import cn.blnp.net.flowable.boot.utils.ListUtils;
import cn.blnp.net.flowable.boot.utils.MultiInstanceExecutionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.variable.api.persistence.entity.VariableInstance;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.*;

/**
 * <h3>流程动态加签、减签案例演示</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/6/19 17:21
 */
@Slf4j
@SpringBootTest
public class DynamicAddSignTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private TaskRecallService taskRecallService;

    SimplePropertyPreFilter executionFilter = new SimplePropertyPreFilter(Execution.class,
            "id", "parentId", "businessKey", "processInstanceId", "scope", "activityId");
    SimplePropertyPreFilter variableFilter =
            new SimplePropertyPreFilter(VariableInstance.class,
                    "name", "executionId", "value");

    /**
     *  <h2>加签、减签用例</h2>
     *  <ul>
     *      <li><b>流程定义文件：</b>{@link flow/multiInstanceUserTaskProcess.bpmn20.xml}</li>
     *      <li>
     *          <b>流程预览图：</b></br>
     *          <img src="https://cdn4.winhlb.com/2025/06/19/6853d7027007f.png" >
     *      </li>
     *  </ul>
     **/
    @SneakyThrows
    @Test
    public void test() {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/multiInstanceUserTaskProcess.bpmn20.xml")
                .name("流程加减签演示案例")
                .deploy();
        log.info("部署ID：{}", deploy.getId());
        //流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义ID：{}", processDefinition.getId());

        //初始化流程启动参数
        List<String> assigneeList1 = new ArrayList<>();
        assigneeList1.add("张三");
        assigneeList1.add("李四");
        List<String> assigneeList2 = new ArrayList<>();
        assigneeList2.add("安琪拉");
        assigneeList2.add("妲己");
        Map<String, Object> variables = MapUtil.builder(new HashMap<String, Object>())
                .put("assigneeList1", assigneeList1)
                .put("assigneeList2", assigneeList2)
                .build();

        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(processDefinition.getId(), variables);
        log.info("流程实例ID：{}", procInst.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询第一个节点的任务
        Task firstTask = taskQuery.singleResult();
        //完成第一个节点的任务
        taskService.complete(firstTask.getId());
        log.info("用户任务{}办理完成", firstTask.getName());
        //查询第二个节点的任务
        List<Task> taskOfSecondNode = taskQuery.list();
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(), taskOfSecondNode.get(0).getName(),
                "执行加签前");
        MultiInstanceExecutionUtil multiInstanceExecutionUtil =
                new MultiInstanceExecutionUtil(repositoryService, runtimeService,
                        taskService);

        //执行加签两个人
        multiInstanceExecutionUtil.addSign("assigneeList1", "assignee",
                procInst.getId(), taskOfSecondNode.get(0),
                Arrays.asList("妮露", "申鹤"));
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(),
                taskOfSecondNode.get(0).getName(), "执行加签后");

        //执行减签一个人
        multiInstanceExecutionUtil.deleteSign("assigneeList1", procInst.getId(),
                taskOfSecondNode.get(0), "张三");
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(),
                taskOfSecondNode.get(0).getName(), "执行减签后");
        List<Task> taskList1 = taskQuery.list();
        //办理完成第二个节点的所有任务
        for (Task task : taskList1) {
            taskService.complete(task.getId());
            log.info("{}办理完成{}的用户任务", task.getAssignee(), task.getName());
            Thread.sleep(500);
        }
        //查询第三个节点的任务
        Task thirdTask = taskQuery.singleResult();
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(), thirdTask.getName(), "执行加签前");

        //执行加签两个人
        multiInstanceExecutionUtil.addSign("assigneeList2", "assignee",
                procInst.getId(), thirdTask, Arrays.asList("大乔", "小乔"));
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(), thirdTask.getName(), "执行加签后");

        //执行减签一个人
        multiInstanceExecutionUtil.deleteSign("assigneeList2", procInst.getId(),
                thirdTask, "安琪拉");
        //输出执行实例和变量信息
        logExecutionAndVariableData(procInst.getId(), thirdTask.getName(), "执行减签后");
        //办理完成第三个节点的所有任务
        for (int i = 0; i < 3; i++) {
            Task task = taskQuery.singleResult();
            taskService.complete(task.getId());
            log.info("{}办理完成用户任务：{}", task.getAssignee(), task.getName());
        }
        //查询第四个节点的任务
        Task forthTask = taskQuery.singleResult();
        log.info("流程流转到：{}", forthTask.getName());

        /**
         *  结果演示：
         *  2025-06-19 17:39:07.348  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 部署ID：260001
         * 2025-06-19 17:39:07.355  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 流程定义ID：multiInstanceUserTaskProcess:5:260004
         * 2025-06-19 17:39:07.407  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 流程实例ID：260005
         * 2025-06-19 17:39:07.489  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 用户任务上线申请办理完成
         * 2025-06-19 17:39:07.718  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行加签前的执行实例数为4，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask2","id":"260019","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260023","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260024","parentId":"260019","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:07.748  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行加签前的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["安琪拉","妲己"]},{"executionId":"260005","name":"assigneeList1","value":["张三","李四"]},{"executionId":"260019","name":"nrOfInstances","value":2},{"executionId":"260019","name":"nrOfCompletedInstances","value":0},{"executionId":"260019","name":"nrOfActiveInstances","value":2},{"executionId":"260023","name":"assignee","value":"张三"},{"executionId":"260024","name":"assignee","value":"李四"},{"executionId":"260023","name":"loopCounter","value":0},{"executionId":"260024","name":"loopCounter","value":1}]
         * 2025-06-19 17:39:07.901  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行加签后的执行实例数为6，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask2","id":"260019","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260023","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260024","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260039","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260047","parentId":"260019","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:07.911  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行加签后的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["安琪拉","妲己"]},{"executionId":"260005","name":"assigneeList1","value":["张三","李四","妮露","申鹤"]},{"executionId":"260019","name":"nrOfInstances","value":6},{"executionId":"260019","name":"nrOfCompletedInstances","value":2},{"executionId":"260019","name":"nrOfActiveInstances","value":4},{"executionId":"260023","name":"assignee","value":"张三"},{"executionId":"260024","name":"assignee","value":"李四"},{"executionId":"260023","name":"loopCounter","value":0},{"executionId":"260024","name":"loopCounter","value":1},{"executionId":"260039","name":"assignee","value":"妮露"},{"executionId":"260039","name":"loopCounter","value":4},{"executionId":"260047","name":"assignee","value":"申鹤"},{"executionId":"260047","name":"loopCounter","value":5}]
         * 2025-06-19 17:39:08.035  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行减签后的执行实例数为5，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask2","id":"260019","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260024","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260039","parentId":"260019","processInstanceId":"260005","scope":false},{"activityId":"userTask2","id":"260047","parentId":"260019","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:08.047  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 平台管理员审批节点执行减签后的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["安琪拉","妲己"]},{"executionId":"260005","name":"assigneeList1","value":["李四","妮露","申鹤"]},{"executionId":"260019","name":"nrOfInstances","value":4},{"executionId":"260019","name":"nrOfCompletedInstances","value":1},{"executionId":"260019","name":"nrOfActiveInstances","value":3},{"executionId":"260024","name":"assignee","value":"李四"},{"executionId":"260024","name":"loopCounter","value":1},{"executionId":"260039","name":"assignee","value":"妮露"},{"executionId":"260039","name":"loopCounter","value":4},{"executionId":"260047","name":"assignee","value":"申鹤"},{"executionId":"260047","name":"loopCounter","value":5}]
         * 2025-06-19 17:39:08.102  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 李四办理完成平台管理员审批的用户任务
         * 2025-06-19 17:39:08.639  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 妮露办理完成平台管理员审批的用户任务
         * 2025-06-19 17:39:09.220  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 申鹤办理完成平台管理员审批的用户任务
         * 2025-06-19 17:39:09.740  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行加签前的执行实例数为3，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask3","id":"260061","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask3","id":"260062","parentId":"260061","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:09.743  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行加签前的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["安琪拉","妲己"]},{"executionId":"260005","name":"assigneeList1","value":["李四","妮露","申鹤"]},{"executionId":"260061","name":"nrOfInstances","value":2},{"executionId":"260061","name":"nrOfCompletedInstances","value":0},{"executionId":"260061","name":"nrOfActiveInstances","value":1},{"executionId":"260062","name":"assignee","value":"安琪拉"},{"executionId":"260062","name":"loopCounter","value":0}]
         * 2025-06-19 17:39:09.772  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行加签后的执行实例数为3，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask3","id":"260061","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask3","id":"260062","parentId":"260061","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:09.774  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行加签后的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["安琪拉","妲己","大乔","小乔"]},{"executionId":"260005","name":"assigneeList1","value":["李四","妮露","申鹤"]},{"executionId":"260061","name":"nrOfInstances","value":4},{"executionId":"260061","name":"nrOfCompletedInstances","value":0},{"executionId":"260061","name":"nrOfActiveInstances","value":1},{"executionId":"260062","name":"assignee","value":"安琪拉"},{"executionId":"260062","name":"loopCounter","value":0}]
         * 2025-06-19 17:39:09.803  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行减签后的执行实例数为3，分别是：[{"id":"260005","processInstanceId":"260005","scope":true},{"activityId":"userTask3","id":"260061","parentId":"260005","processInstanceId":"260005","scope":false},{"activityId":"userTask3","id":"260062","parentId":"260061","processInstanceId":"260005","scope":false}]
         * 2025-06-19 17:39:09.806  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 运维管理员操作节点执行减签后的流程变量为：[{"executionId":"260005","name":"assigneeList2","value":["妲己","大乔","小乔"]},{"executionId":"260005","name":"assigneeList1","value":["李四","妮露","申鹤"]},{"executionId":"260061","name":"nrOfInstances","value":3},{"executionId":"260061","name":"nrOfCompletedInstances","value":0},{"executionId":"260061","name":"nrOfActiveInstances","value":1},{"executionId":"260062","name":"assignee","value":"安琪拉"},{"executionId":"260062","name":"loopCounter","value":0}]
         * 2025-06-19 17:39:09.839  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 安琪拉办理完成用户任务：运维管理员操作
         * 2025-06-19 17:39:09.871  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 大乔办理完成用户任务：运维管理员操作
         * 2025-06-19 17:39:09.900  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 小乔办理完成用户任务：运维管理员操作
         * 2025-06-19 17:39:09.901  INFO 49628 --- [           main] c.b.n.f.b.l.d.sign.DynamicAddSignTest    : 流程流转到：测试负责人验收
         **/
    }

    /**
     * <p><b>用途:输出执行实例与变量信息<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 17:27 2025/6/19
     * @params [processInstanceId, taskName, operate]
     * @param processInstanceId 流程实例ID
     * @param taskName 任务名称
     * @param operate 操作名称
     * @return void
    **/
    private void logExecutionAndVariableData(String processInstanceId, String taskName, String operate) {
        List<Execution> executionList = runtimeService.createExecutionQuery()
                .processInstanceId(processInstanceId).list();
        log.info("{}节点{}的执行实例数为{}，分别是：{}", taskName, operate,
                executionList.size(),
                JSON.toJSONString(executionList, executionFilter));
        List<VariableInstance> variables = runtimeService.createVariableInstanceQuery()
                .processInstanceId(processInstanceId).list();
        log.info("{}节点{}的流程变量为：{}", taskName, operate,
                JSON.toJSONString(variables, variableFilter));
    }
}
